/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
// 数码管引脚定义
#define HC595_DATA_Pin GPIO_PIN_3
#define HC595_DATA_Port GPIOB
#define HC595_SCLK_Pin GPIO_PIN_5
#define HC595_SCLK_Port GPIOB
#define HC595_LCLK_Pin GPIO_PIN_4
#define HC595_LCLK_Port GPIOB
#define HC138_A0_Pin GPIO_PIN_11
#define HC138_A0_Port GPIOC
#define HC138_A1_Pin GPIO_PIN_12
#define HC138_A1_Port GPIOC
#define HC138_A2_Pin GPIO_PIN_2
#define HC138_A2_Port GPIOD

// 数码管段码（共阴）
uint8_t SEGMENT[17] = {
    0x3F, 0x06, 0x5B, 0x4F, 0x66, 
    0x6D, 0x7D, 0x07, 0x7F, 0x6F, 
    0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x00
};

// 数码管位选
uint8_t DIGIT_SEL[4] = {0x00, 0x01, 0x02, 0x03};

// 倒计时参数
#define TOTAL_TIME    10  // 总倒计时30秒
#define WARNING_TIME  7   // 最后7秒警告

// OLED参数
#define OLED_ADDR     0x78
#define OLED_CMD      0x00
#define OLED_DATA     0x40

// 蜂鸣器、LED引脚
#define BUZZER_PIN    GPIO_PIN_7
#define BUZZER_PORT   GPIOC
#define LED1_PIN      GPIO_PIN_1
#define LED1_PORT     GPIOC
#define LED2_PIN      GPIO_PIN_2
#define LED2_PORT     GPIOC
#define LED3_PIN      GPIO_PIN_3
#define LED3_PORT     GPIOC

// 新增："开始喽~"和"要爆炸喽~"的字模（阴码、列行式、逆向）
const uint8_t CUSTOM_FONT[][32] = {
    // 开始喽~：开(0)、始(1)、喽(2)、~(3)
    {0x80,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0x80,0x00,
     0x00,0x80,0x40,0x30,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00},/*"开",0*/
    {0x10,0x10,0xF0,0x1F,0x10,0xF0,0x00,0x40,0xE0,0x58,0x47,0x40,0x50,0x60,0xC0,0x00,
     0x40,0x22,0x15,0x08,0x16,0x21,0x00,0x00,0xFE,0x42,0x42,0x42,0x42,0xFE,0x00,0x00},/*"始",1*/
    {0x00,0xFC,0x04,0x04,0xFC,0x00,0x90,0x52,0x34,0x10,0x7F,0x10,0x34,0x52,0x90,0x00,
     0x00,0x0F,0x04,0x04,0x0F,0x82,0x82,0x5A,0x56,0x23,0x22,0x52,0x4E,0x82,0x02,0x00},/*"喽",2*/
    {0x00,0x02,0x01,0x02,0x02,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",3*/

    // 要爆炸喽~：要(0)、爆(1)、炸(2)、喽(3)、~(4)
    {0x00,0x02,0xF2,0x92,0x92,0xFE,0x92,0x92,0x92,0xFE,0x92,0x92,0xF2,0x02,0x00,0x00,
     0x00,0x02,0x82,0x92,0x9A,0x56,0x63,0x22,0x32,0x4A,0x46,0x42,0x82,0x02,0x00,0x00},/*"要",0*/
    {0x80,0x70,0x00,0xFF,0x10,0x08,0x40,0x5F,0xF5,0x55,0x55,0x55,0xF5,0x5F,0x40,0x00,
     0x80,0x60,0x18,0x07,0x08,0x11,0x09,0x45,0x2B,0x91,0xFD,0x11,0x2B,0x45,0x09,0x00},/*"爆",1*/
    {0x80,0x70,0x00,0xFF,0x10,0x48,0x30,0x0F,0xF8,0x88,0x88,0x88,0x88,0x08,0x08,0x00,
     0x80,0x60,0x18,0x07,0x08,0x30,0x00,0x00,0xFF,0x08,0x08,0x08,0x08,0x08,0x00,0x00},/*"炸",2*/
    {0x00,0xFC,0x04,0x04,0xFC,0x00,0x90,0x52,0x34,0x10,0x7F,0x10,0x34,0x52,0x90,0x00,
     0x00,0x0F,0x04,0x04,0x0F,0x82,0x82,0x5A,0x56,0x23,0x22,0x52,0x4E,0x82,0x02,0x00},/*"喽",3*/
    {0x00,0x02,0x01,0x02,0x02,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",4*/
};

// OLED缓冲区
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define BUFFER_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 8)
uint8_t OLED_Buffer[BUFFER_SIZE];

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t countdown = TOTAL_TIME;  // 倒计时变量
uint8_t digit_buffer[2] = {3, 0}; // 数码管显示缓冲区（十位、个位）
uint8_t in_warning = 0;          // 是否进入警告状态
uint8_t led_state = 0;           // LED闪烁状态

uint8_t buzzer_state = 0;   //蜂鸣器当前状态
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
// 数码管驱动
void HC595_WriteByte(uint8_t data);
void HC138_SelectDigit(uint8_t digit);
void update_digit_buffer(void);
void display_digit_scan(void);

// OLED驱动（使用新的显示方法）
void OLED_WriteCommand(uint8_t cmd);
void OLED_WriteData(uint8_t data);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_UpdateDisplay(void);
void OLED_DrawChar16x16(int16_t x, uint8_t page, const uint8_t* char_data);
void OLED_DrawText(uint8_t x, uint8_t y, uint8_t start_index, uint8_t char_count); // 修改这里
void OLED_ShowCustomString_Start(uint8_t x, uint8_t y);
void OLED_ShowCustomString_Boom(uint8_t x, uint8_t y);
void my_memset(uint8_t *ptr, uint8_t value, uint32_t size);
void OLED_ClearBuffer(void);

// 外设控制
void buzzer_control(uint8_t enable);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/**
  * @brief  向74HC595写入1字节数据
  * @param  data: 要写入的数据
  * @retval None
  */
void HC595_WriteByte(uint8_t data) {
    for (int i = 0; i < 8; i++) {
        HAL_GPIO_WritePin(HC595_SCLK_Port, HC595_SCLK_Pin, GPIO_PIN_RESET);
        if (data & 0x80) {
            HAL_GPIO_WritePin(HC595_DATA_Port, HC595_DATA_Pin, GPIO_PIN_SET);
        } else {
            HAL_GPIO_WritePin(HC595_DATA_Port, HC595_DATA_Pin, GPIO_PIN_RESET);
        }
        HAL_GPIO_WritePin(HC595_SCLK_Port, HC595_SCLK_Pin, GPIO_PIN_SET);
        data <<= 1;
    }
    HAL_GPIO_WritePin(HC595_LCLK_Port, HC595_LCLK_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(HC595_LCLK_Port, HC595_LCLK_Pin, GPIO_PIN_SET);
}

/**
  * @brief  选择数码管位（HC138译码）
  * @param  digit: 数码管位索引（0~3）
  * @retval None
  */
void HC138_SelectDigit(uint8_t digit) {
    uint8_t addr = DIGIT_SEL[digit];
    HAL_GPIO_WritePin(HC138_A2_Port, HC138_A2_Pin, (addr & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(HC138_A1_Port, HC138_A1_Pin, (addr & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(HC138_A0_Port, HC138_A0_Pin, (addr & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

/**
  * @brief  更新数码管显示缓冲区
  * @retval None
  */
void update_digit_buffer(void) {
    digit_buffer[0] = countdown / 10;  // 十位
    digit_buffer[1] = countdown % 10;  // 个位
}

/**
  * @brief  数码管动态扫描显示
  * @retval None
  */
void display_digit_scan(void) {
    for (int i = 0; i < 2; i++) { // 仅显示2位（倒计时00~30）
        HC138_SelectDigit(i);
        HC595_WriteByte(SEGMENT[digit_buffer[i]]);
        HAL_Delay(1);
    }
}

/**
  * @brief  向OLED写入命令
  * @param  cmd: 命令字节
  * @retval None
  */
void OLED_WriteCommand(uint8_t cmd) {
   uint8_t buf[2] = {0x00, cmd};
  HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, buf, 2, 100);
}

/**
  * @brief  向OLED写入数据
  * @param  data: 数据字节
  * @retval None
  */
void OLED_WriteData(uint8_t data) {
   uint8_t buf[2] = {0x40, data};
  HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, buf, 2, 100);
}

/**
  * @brief  OLED初始化
  * @retval None
  */
void OLED_Init(void) {
    HAL_Delay(200);

    OLED_WriteCommand(0xAE);    // 关闭显示
    OLED_WriteCommand(0xA0);    // 设置段重映射
    OLED_WriteCommand(0xC0);    // 设置COM输出扫描方向
    OLED_WriteCommand(0x20);    // 设置内存地址模式
    OLED_WriteCommand(0x00);    // 水平寻址模式
    OLED_WriteCommand(0x81);    // 设置对比度控制
    OLED_WriteCommand(0xCF);    // 对比度值
    OLED_WriteCommand(0xA6);    // 设置正常显示
    OLED_WriteCommand(0xA8);    // 设置多路复用率
    OLED_WriteCommand(0x3F);    // 64行
    OLED_WriteCommand(0xD3);    // 设置显示偏移
    OLED_WriteCommand(0x00);    // 无偏移
    OLED_WriteCommand(0x40);    // 设置显示开始行
    OLED_WriteCommand(0x8D);    // 设置电荷泵
    OLED_WriteCommand(0x14);    // 开启电荷泵
    OLED_WriteCommand(0xAF);    // 开启显示
    
    HAL_Delay(100);
    OLED_ClearBuffer();
    OLED_UpdateDisplay();
}
/**
  * @brief  清空OLED显示
  * @retval None
  */
void OLED_Clear(void) {
    my_memset(OLED_Buffer, 0, BUFFER_SIZE);
    OLED_UpdateDisplay();
}

/**
  * @brief  内存设置函数
  * @param  ptr: 目标指针
  * @param  value: 设置的值
  * @param  size: 大小
  * @retval None
  */
void my_memset(uint8_t *ptr, uint8_t value, uint32_t size) {
    for (uint32_t i = 0; i < size; i++) {
        ptr[i] = value;
    }
}

/**
  * @brief  清空OLED缓冲区
  * @retval None
  */
void OLED_ClearBuffer(void) {
    my_memset(OLED_Buffer, 0, BUFFER_SIZE);
}

/**
  * @brief  更新OLED显示
  * @retval None
  */
void OLED_UpdateDisplay(void) {
    for (uint8_t page = 0; page < 8; page++) {
        OLED_WriteCommand(0xB0 + page);  // 设置页地址
        OLED_WriteCommand(0x00);         // 设置低列地址
        OLED_WriteCommand(0x10);         // 设置高列地址
        
        for (uint8_t col = 0; col < SCREEN_WIDTH; col++) {
            OLED_WriteData(OLED_Buffer[page * SCREEN_WIDTH + col]);
        }
    }
}

/* USER CODE BEGIN 0 */

/**
  * @brief  绘制16x16字符到缓冲区
  * @param  x: 列坐标
  * @param  page: 页坐标
  * @param  char_data: 字符数据
  * @retval None
  */
void OLED_DrawChar16x16(int16_t x, uint8_t page, const uint8_t* char_data) {
    // 仅当字符部分可见时才绘制
    if (x + 16 < 0 || x >= SCREEN_WIDTH)
        return;

    // 绘制字符上半部分
    for (uint8_t i = 0; i < 16; i++) {
        int16_t col = x + i;
        if (col >= 0 && col < SCREEN_WIDTH) {
            OLED_Buffer[page * SCREEN_WIDTH + col] = char_data[i];
        }
    }
    
    // 绘制字符下半部分
    for (uint8_t i = 16; i < 32; i++) {
        int16_t col = x + (i - 16);
        if (col >= 0 && col < SCREEN_WIDTH) {
            OLED_Buffer[(page + 1) * SCREEN_WIDTH + col] = char_data[i];
        }
    }
}

/**
  * @brief  绘制文本到缓冲区
  * @param  x: 起始列坐标
  * @param  y: 起始页坐标
  * @param  start_index: 起始字符索引
  * @param  char_count: 字符数量
  * @retval None
  */
void OLED_DrawText(uint8_t x, uint8_t y, uint8_t start_index, uint8_t char_count) {
    for (uint8_t i = 0; i < char_count; i++) {
        int16_t char_x = x + i * 16;
        OLED_DrawChar16x16(char_x, y, CUSTOM_FONT[start_index + i]);
    }
}

/**
  * @brief  显示"开始喽~"
  * @param  x: 列坐标
  * @param  y: 页坐标
  * @retval None
  */
void OLED_ShowCustomString_Start(uint8_t x, uint8_t y) {
    OLED_ClearBuffer();
    OLED_DrawText(x, y, 0, 4);
    OLED_UpdateDisplay();
}

/**
  * @brief  显示"要爆炸喽~"
  * @param  x: 列坐标
  * @param  y: 页坐标
  * @retval None
  */
void OLED_ShowCustomString_Boom(uint8_t x, uint8_t y) {
    OLED_ClearBuffer();
    OLED_DrawText(x, y, 4, 5);
    OLED_UpdateDisplay();
}




/**
  * @brief  在OLED上显示字符串
  * @param  x: X坐标
  * @param  y: Y坐标
  * @param  str: 字符串指针
  * @retval None
  */
//void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *str) {
//    uint8_t char_index = 0;
//    for(uint8_t i = 0; i < 4; i++) { // 共4个字符：开、始、喽、~
//        // 设置字符位置
//        OLED_WriteCmd(0xB0 + y);                  // 页地址
//        OLED_WriteCmd(((x & 0xF0) >> 4) | 0x10);  // 列地址高位
//        OLED_WriteCmd(x & 0x0F);                  // 列地址低位
//        // 写入上半页（8行）
//        for(uint8_t j = 0; j < 8; j++) {
//            OLED_WriteData(CUSTOM_FONT[char_index][j]);
//        }
//        OLED_WriteCmd(0xB0 + (y + 1));            // 下一页地址
//        OLED_WriteCmd(((x & 0xF0) >> 4) | 0x10);  // 列地址高位
//        OLED_WriteCmd(x & 0x0F);                  // 列地址低位
//        // 写入下半页（8行）
//        for(uint8_t j = 8; j < 16; j++) {
//            OLED_WriteData(CUSTOM_FONT[char_index][j]);
//        }
//        x += 16; // 每个字符占16列，右移16列
//        char_index++;
//    }
//}
/**
  * @brief  控制蜂鸣器
  * @param  enable: 1-开启，0-关闭
  * @retval None
  */
void buzzer_control(uint8_t enable) {
    HAL_GPIO_WritePin(BUZZER_PORT, BUZZER_PIN, enable ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

/**
  * @brief  定时器中断回调函数
  * @param  htim: 定时器句柄
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if(htim->Instance == TIM2) { // TIM2：1秒倒计时
        if(countdown > 0) {
            countdown--;
            update_digit_buffer();
            
            // 检查是否进入警告状态
            if(countdown <= WARNING_TIME && !in_warning) {
                in_warning = 1;
                OLED_Clear();
                OLED_ShowCustomString_Boom(8, 3);
                //buzzer_control(1); // 开启蜂鸣器
                HAL_TIM_Base_Start_IT(&htim3); // 启动TIM3控制LED闪烁
            }
        } else {
					  in_warning = 0;
            HAL_TIM_Base_Stop_IT(&htim2); // 停止TIM2
            //buzzer_control(0); // 关闭蜂鸣器
            HAL_TIM_Base_Stop_IT(&htim3); // 停止TIM3
					//倒计时结束显示提示
					OLED_Clear();
        }
    } else if(htim->Instance == TIM3) { // TIM3：200ms LED闪烁
        if(in_warning) {
            // 3个LED交替闪烁
            HAL_GPIO_WritePin(LED1_PORT, LED1_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(LED2_PORT, LED2_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(LED3_PORT, LED3_PIN, GPIO_PIN_RESET);
            
            switch(led_state) {
                case 0: HAL_GPIO_WritePin(LED1_PORT, LED1_PIN, GPIO_PIN_SET); break;
                case 1: HAL_GPIO_WritePin(LED2_PORT, LED2_PIN, GPIO_PIN_SET); break;
                case 2: HAL_GPIO_WritePin(LED3_PORT, LED3_PIN, GPIO_PIN_SET); break;
            }
            led_state = (led_state + 1) % 3;
						
						buzzer_state = !buzzer_state;    //翻转状态
						buzzer_control(buzzer_state);    //翻转后的状态控制蜂鸣器
        }else{
					buzzer_control(0);
					buzzer_state = 0;
				}
    }
}


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
  // 初始化LED为关闭状态
  HAL_GPIO_WritePin(LED1_PORT, LED1_PIN, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(LED2_PORT, LED2_PIN, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(LED3_PORT, LED3_PIN, GPIO_PIN_RESET);
  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_I2C1_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	
  update_digit_buffer(); // 初始化数码管显示
  OLED_Init();    	// 初始化OLED
	HAL_Delay(200);
	OLED_Clear();
	HAL_Delay(100);
	
	//显示倒计时文本
	OLED_ShowCustomString_Start(16, 3);
	__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
  HAL_TIM_Base_Start_IT(&htim2);           // 启动倒计时定时器
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    display_digit_scan(); // 持续刷新数码管
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
    // 错误时LED快速闪烁
    HAL_GPIO_TogglePin(LED1_PORT, LED1_PIN);
    HAL_Delay(100);
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
